import socket
import threading
import time
import tkinter as tk
from datetime import datetime
from tkinter import ttk, scrolledtext

import ttkbootstrap as ttk
from ttkbootstrap.constants import *

from app.util.annotation_util import annotate, ClassInfo
from app.util.device_data_validator import DeviceValidator
from app.util.rogercam_au_test import construct_protocol
from app.view.base_view import View


@annotate(ClassInfo(name="FtAuCardConfig", category="ft_tool"))
class FtAuCardConfigView(View):
    """设置视图"""

    def __init__(self, parent, controller):
        super().__init__(parent, controller)

        # 服务器相关变量
        self.server_socket = None
        self.is_running = False
        self.server_thread = None
        self.clients = {}  # 存储连接的客户端 {client_address: (socket, thread)}
        self.selected_client = None

        # IP过滤变量
        self.filter_var = ttk.StringVar()
        self.filter_var.trace_add("write", self.on_filter_var_change)
        # 创建UI
        self.create_ui()

        # 绑定关闭事件
        # self.protocol("WM_DELETE_WINDOW", self.on_close)

    def create_ui(self):
        """创建用户界面"""
        # 主框架
        self.main_frame = ttk.Frame(self, padding=10)
        self.main_frame.pack(fill=BOTH, expand=True)

        # 顶部服务器控制区
        self.create_server_control()

        # 创建分隔符
        ttk.Separator(self.main_frame, orient=HORIZONTAL).pack(fill=X, pady=5)

        # 中间内容区（左侧命令生成，右侧客户端列表）
        content_frame = ttk.Frame(self.main_frame)
        content_frame.pack(fill=BOTH, expand=True, pady=5)

        # 左侧命令生成区
        left_frame = ttk.Frame(content_frame)
        left_frame.pack(side=LEFT, fill=BOTH, expand=True, padx=5)
        self.create_command_generator(left_frame)

        # 右侧客户端列表区
        right_frame = ttk.Frame(content_frame)
        right_frame.pack(side=RIGHT, fill=BOTH, expand=True, padx=5)
        self.create_client_list(right_frame)

        # 创建分隔符
        ttk.Separator(self.main_frame, orient=HORIZONTAL).pack(fill=X, pady=5)

        # 底部日志区
        self.create_log_area()

    def create_server_control(self):
        """创建服务器控制区域"""
        control_frame = ttk.LabelFrame(self.main_frame, text="服务器控制", padding=10)
        control_frame.pack(fill=X, pady=5)

        # 端口设置
        ttk.Label(control_frame, text="端口:").pack(side=LEFT, padx=5)
        self.port_var = tk.StringVar(value="14121")
        ttk.Entry(control_frame, textvariable=self.port_var, width=10).pack(side=LEFT, padx=5)

        # 服务器状态
        self.status_var = tk.StringVar(value="未运行")
        ttk.Label(control_frame, text="状态:").pack(side=LEFT, padx=(20, 5))
        ttk.Label(control_frame, textvariable=self.status_var, bootstyle=DANGER).pack(side=LEFT, padx=5)

        # 启动/停止按钮
        self.start_stop_btn = ttk.Button(
            control_frame,
            text="启动服务器",
            command=self.toggle_server,
            bootstyle=SUCCESS
        )
        self.start_stop_btn.pack(side=RIGHT, padx=5)

    def create_command_generator(self, parent):
        """创建命令生成区域"""
        command_frame = ttk.LabelFrame(parent, text="命令生成", padding=10)
        command_frame.pack(fill=BOTH, expand=True)

        # 输入字段区域
        input_frame = ttk.Frame(command_frame)
        input_frame.pack(fill=X, pady=5)

        # 设备ID
        ttk.Label(input_frame, text="设备ID:").grid(row=0, column=0, sticky=W, pady=5, padx=5)
        self.device_id_var = tk.StringVar()
        ttk.Entry(input_frame, textvariable=self.device_id_var).grid(row=0, column=1, sticky=EW, pady=5, padx=5)

        # MAC地址输入
        ttk.Label(input_frame, text="MAC1:").grid(row=1, column=0, sticky=W, pady=5, padx=5)
        self.mac1_var = tk.StringVar()
        ttk.Entry(input_frame, textvariable=self.mac1_var).grid(row=1, column=1, sticky=EW, pady=5, padx=5)

        ttk.Label(input_frame, text="MAC2:").grid(row=2, column=0, sticky=W, pady=5, padx=5)
        self.mac2_var = tk.StringVar()
        ttk.Entry(input_frame, textvariable=self.mac2_var).grid(row=2, column=1, sticky=EW, pady=5, padx=5)

        ttk.Label(input_frame, text="MAC3:").grid(row=3, column=0, sticky=W, pady=5, padx=5)
        self.mac3_var = tk.StringVar()
        ttk.Entry(input_frame, textvariable=self.mac3_var).grid(row=3, column=1, sticky=EW, pady=5, padx=5)

        ttk.Label(input_frame, text="MAC4:").grid(row=4, column=0, sticky=W, pady=5, padx=5)
        self.mac4_var = tk.StringVar()
        ttk.Entry(input_frame, textvariable=self.mac4_var).grid(row=4, column=1, sticky=EW, pady=5, padx=5)

        # 设置列权重，使输入框可以拉伸
        input_frame.columnconfigure(1, weight=1)

        # 生成命令和清除按钮区域
        generate_buttons_frame = ttk.Frame(command_frame)
        generate_buttons_frame.pack(fill=X, pady=10)

        # 生成命令按钮
        ttk.Button(
            generate_buttons_frame,
            text="生成命令",
            command=self.generate_command,
            bootstyle=PRIMARY
        ).pack(side=LEFT, padx=5, fill=X, expand=True)

        # 清除命令预览按钮
        ttk.Button(
            generate_buttons_frame,
            text="清除命令预览",
            command=self.clear_command_preview,
            bootstyle=SECONDARY
        ).pack(side=LEFT, padx=5, fill=X, expand=True)

        # 清除输入按钮
        ttk.Button(
            generate_buttons_frame,
            text="清除输入",
            command=self.clear_input_fields,
            bootstyle=SECONDARY
        ).pack(side=LEFT, padx=5, fill=X, expand=True)

        # 命令预览
        ttk.Label(command_frame, text="命令预览:").pack(anchor=W, pady=(10, 5))
        self.command_preview = scrolledtext.ScrolledText(
            command_frame,
            wrap=tk.WORD,
            height=5
        )
        self.command_preview.pack(fill=X, pady=5)

        # 发送命令和清除日志按钮区域
        send_buttons_frame = ttk.Frame(command_frame)
        send_buttons_frame.pack(fill=X, pady=10)

        # 发送命令按钮
        self.send_btn = ttk.Button(
            send_buttons_frame,
            text="发送命令",
            command=self.send_command,
            bootstyle=SUCCESS
        )
        self.send_btn.pack(side=LEFT, padx=5, fill=X, expand=True)
        self.send_btn.config(state=DISABLED)

        # 清除通信日志按钮
        ttk.Button(
            send_buttons_frame,
            text="清除通信日志",
            command=self.clear_communication_log,
            bootstyle=SECONDARY
        ).pack(side=LEFT, padx=5, fill=X, expand=True)

    def create_client_list(self, parent):
        """创建客户端列表区域"""
        client_frame = ttk.LabelFrame(parent, text="连接的客户端", padding=10)
        client_frame.pack(fill=BOTH, expand=True)

        # 搜索栏
        filter_frame = ttk.Frame(client_frame)
        # MAC地址输入
        ttk.Label(filter_frame, text="IP过滤:").pack(side=LEFT)
        ttk.Entry(filter_frame, textvariable=self.filter_var, width=100).pack(side=RIGHT, fill=X)
        filter_frame.pack(side=TOP, fill=X, pady=5)
        # 客户端列表
        columns = ("id", "device_id", "ip", "port", "status")
        self.client_tree = ttk.Treeview(
            client_frame,
            columns=columns,
            show="headings",
            selectmode=BROWSE
        )

        # 设置列标题和宽度，隐藏id列
        self.client_tree.heading("id", text="ID")
        self.client_tree.heading("device_id", text="设备ID")
        self.client_tree.heading("ip", text="IP地址")
        self.client_tree.heading("port", text="端口")
        self.client_tree.heading("status", text="状态")

        self.client_tree.column("id", width=0, stretch=NO)  # 隐藏id列
        self.client_tree.column("device_id", width=80)
        self.client_tree.column("ip", width=120)
        self.client_tree.column("port", width=80)
        self.client_tree.column("status", width=80)

        # 添加滚动条
        scrollbar = ttk.Scrollbar(
            client_frame,
            orient=VERTICAL,
            command=self.client_tree.yview
        )
        scrollbar.pack(side=RIGHT, fill=Y)
        self.client_tree.configure(yscrollcommand=scrollbar.set)

        self.client_tree.pack(fill=BOTH, expand=True)

        # 绑定选择事件
        self.client_tree.bind("<<TreeviewSelect>>", self.on_client_select)

    def on_filter_var_change(self, *args):
        # 过滤IP列表
        self.update_client_list()
        # current_text = self.filter_var.get()
        # print(f"变量变化: {current_text}")

    def create_log_area(self):
        """创建日志显示区域"""
        log_frame = ttk.LabelFrame(self.main_frame, text="通信日志", padding=10)
        log_frame.pack(fill=BOTH, expand=True, pady=5)

        # 日志文本框
        self.log_text = scrolledtext.ScrolledText(
            log_frame,
            wrap=tk.WORD,
            state=DISABLED
        )
        self.log_text.pack(fill=BOTH, expand=True)

        # 添加日志标签样式
        self.log_text.tag_config("send", foreground="blue")
        self.log_text.tag_config("receive", foreground="green")
        self.log_text.tag_config("info", foreground="black")
        self.log_text.tag_config("error", foreground="red")

    def toggle_server(self):
        """切换服务器状态（启动/停止）"""
        if not self.is_running:
            # 启动服务器
            try:
                port = int(self.port_var.get())
                if not (1 <= port <= 65535):
                    raise ValueError("端口号必须在1-65535之间")

                # 创建服务器套接字
                self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
                self.server_socket.bind(('', port))
                self.server_socket.listen(5)

                # 更新状态
                self.is_running = True
                self.status_var.set(f"运行中 (端口: {port})")
                self.start_stop_btn.config(text="停止服务器", bootstyle=DANGER)
                self.log(f"服务器已启动，监听端口: {port}", "info")

                # 启动服务器线程
                self.server_thread = threading.Thread(target=self.accept_connections, daemon=True)
                self.server_thread.start()

            except Exception as e:
                self.log(f"启动服务器失败: {str(e)}", "error")
                if self.server_socket:
                    self.server_socket.close()
        else:
            # 停止服务器
            self.is_running = False
            if self.server_socket:
                self.server_socket.close()
                self.server_socket = None

            # 关闭所有客户端连接
            for client_addr, (client_socket, _) in self.clients.items():
                try:
                    client_socket.close()
                except:
                    pass
            self.clients.clear()
            self.update_client_list()

            # 更新状态
            self.status_var.set("未运行")
            self.start_stop_btn.config(text="启动服务器", bootstyle=SUCCESS)
            self.log("服务器已停止", "info")

    def accept_connections(self):
        """接受客户端连接"""
        while self.is_running:
            try:
                client_socket, client_addr = self.server_socket.accept()
                client_ip, client_port = client_addr

                # 记录新连接
                self.log(f"新客户端连接: {client_ip}:{client_port}", "info")

                # 创建客户端处理线程
                client_thread = threading.Thread(
                    target=self.handle_client,
                    args=(client_socket, client_addr),
                    daemon=True
                )

                # 存储客户端信息
                self.clients[client_addr] = (client_socket, client_thread)

                # 更新客户端列表
                self.after(10, self.update_client_list)

                # 启动客户端处理线程
                client_thread.start()

            except Exception as e:
                if self.is_running:  # 如果不是主动关闭服务器
                    self.log(f"接受连接错误: {str(e)}", "error")
                break

    def handle_client(self, client_socket, client_addr):
        """处理客户端通信"""
        client_ip, client_port = client_addr
        try:
            while self.is_running:
                # 接收数据
                data = client_socket.recv(1024)
                if not data:
                    break
                # 解码接收到的数据 转化为utf-8 可见字符串
                # message = data.decode('utf-8', errors='replace')
                self.log(f"{client_ip}:{client_port} 接收: {data.hex().upper()}", "receive")

                if len(data) == 12:
                    device_id = f"{data[5:9].hex().upper()}"
                    self.device_id_var.set(device_id)
                    # 更新
                    self.log(f"设备ID:{device_id}", "receive")
                # 自动响应，确认收到消息 限制响应长度
                # client_socket.sendall(data[:50])

        except Exception as e:
            self.log(f"与 {client_ip}:{client_port} 通信错误: {str(e)}", "error")
        finally:
            # 关闭连接
            client_socket.close()
            if client_addr in self.clients:
                del self.clients[client_addr]
                self.after(0, self.update_client_list)
                self.log(f"客户端 {client_ip}:{client_port} 已断开连接", "info")

    def update_client_list(self):
        """更新客户端列表显示"""
        # 保存当前选择
        current_selection = None
        if self.client_tree.selection():
            current_id = self.client_tree.item(self.client_tree.selection()[0])["values"][0]
            current_selection = (current_id.split(":")[0], int(current_id.split(":")[1]))

        # 清空现有列表
        for item in self.client_tree.get_children():
            self.client_tree.delete(item)

        # 添加所有客户端
        for client_addr in self.clients:
            client_ip, client_port = client_addr
            # 使用IP:端口作为唯一标识
            client_id = f"{client_ip}:{client_port}"
            device_id = ""
            if len(self.filter_var.get().strip()) > 0:
                if self.filter_var.get().strip() in client_id:
                    self.client_tree.insert(
                        "",
                        END,
                        values=(client_id, device_id, client_ip, client_port, "连接中")
                    )
            else:
                self.client_tree.insert(
                    "",
                    END,
                    values=(client_id, device_id, client_ip, client_port, "连接中")
                )
        # 恢复选择状态
        if current_selection and current_selection in self.clients:
            for item in self.client_tree.get_children():
                item_id = self.client_tree.item(item)["values"][0]
                if item_id == f"{current_selection[0]}:{current_selection[1]}":
                    self.client_tree.selection_set(item)
                    self.on_client_select(None)
                    break
        else:
            # 如果没有选中的客户端或选中的客户端已断开，禁用发送按钮
            self.selected_client = None
            self.send_btn.config(state=DISABLED)

    def on_client_select(self, event):
        """客户端选择事件"""
        selection = self.client_tree.selection()
        if selection:
            # 获取选中的客户端信息
            item = self.client_tree.item(selection[0])
            client_id, device_id, ip, port, _ = item["values"]
            self.selected_client = (ip, int(port))

            # 启用发送按钮
            if self.selected_client in self.clients:
                self.send_btn.config(state=NORMAL)
                self.log(f"已选择客户端: {ip}:{port}:{device_id}", "info")
            else:
                self.send_btn.config(state=DISABLED)
        else:
            self.selected_client = None
            self.send_btn.config(state=DISABLED)

    def generate_command(self):
        """生成命令"""
        # 获取输入值
        device_id = self.device_id_var.get().strip()
        mac1 = self.mac1_var.get().strip()
        mac2 = self.mac2_var.get().strip()
        mac3 = self.mac3_var.get().strip()
        mac4 = self.mac4_var.get().strip()

        # 验证输入
        if not device_id:
            self.log("设备ID不能为空", "error")
            return

        if not DeviceValidator.validate_device_id(device_id)[0]:
            self.log(f"DeviceID:{DeviceValidator.validate_device_id(device_id)[1]}", "error")
            return

        if not DeviceValidator.validate_mac(mac1)[0]:
            self.log(f"MAC1:{DeviceValidator.validate_mac(mac1)[1]}", "error")
            return
        if not DeviceValidator.validate_mac(mac2)[0]:
            self.log(f"MAC2:{DeviceValidator.validate_mac(mac2)[1]}", "error")
            return
        if not DeviceValidator.validate_mac(mac3)[0]:
            self.log(f"MAC3:{DeviceValidator.validate_mac(mac3)[1]}", "error")
            return
        if not DeviceValidator.validate_mac(mac4)[0]:
            self.log(f"MAC4:{DeviceValidator.validate_mac(mac4)[1]}", "error")
            return

        mac1 = mac1.upper().replace("-", "")
        mac2 = mac2.upper().replace("-", "")
        mac3 = mac3.upper().replace("-", "")
        mac4 = mac4.upper().replace("-", "")
        # AT命令
        command = f"AT+WRITEBINDMAC={mac1},{mac2},{mac3},{mac4},000000000000,000000000000,000000000000,1DB4C8B61A1C\r\n"
        if isinstance(device_id, str):
            device_id = int(device_id, 16)
        command = construct_protocol(int(device_id).to_bytes(4, byteorder='big'), bytes(command, 'utf-8'))
        # 转换为JSON字符串
        try:
            self.command_preview.delete(1.0, tk.END)
            self.command_preview.insert(tk.END, command)
            self.log("命令生成成功", "info")
        except Exception as e:
            self.log(f"命令生成失败: {str(e)}", "error")

    def clear_command_preview(self):
        """清除命令预览区域"""
        self.command_preview.delete(1.0, tk.END)
        self.log("命令预览已清除", "info")

    def clear_input_fields(self):
        """清除所有输入字段（设备ID和MAC地址）"""
        self.device_id_var.set("")
        self.mac1_var.set("")
        self.mac2_var.set("")
        self.mac3_var.set("")
        self.mac4_var.set("")
        self.log("输入字段已清除", "info")

    def clear_communication_log(self):
        """清除通信日志"""
        self.log_text.config(state=NORMAL)
        self.log_text.delete(1.0, tk.END)
        self.log_text.config(state=DISABLED)
        self.log("通信日志已清除", "info")

    def send_command(self):
        """发送命令到选中的客户端"""
        if not self.selected_client or self.selected_client not in self.clients:
            self.log("未选中有效客户端", "error")
            self.send_btn.config(state=DISABLED)
            return
        self.generate_command()
        # 获取预览的命令
        command_str = self.command_preview.get(1.0, tk.END).strip()
        if not command_str:
            self.log("命令不能为空，请先生成命令", "error")
            return

        # 获取客户端套接字
        client_socket, _ = self.clients[self.selected_client]
        client_ip, client_port = self.selected_client

        try:
            device_id = int(self.device_id_var.get().strip(), 16).to_bytes(4, byteorder='big')
            client_socket.sendall(
                bytes(construct_protocol(
                    device_id,
                    bytes("+++", 'utf-8')),
                    'utf-8')
            )
            time.sleep(0.1)
            # 发送命令
            client_socket.sendall(bytes.fromhex(command_str))
            time.sleep(0.1)
            client_socket.sendall(bytes(construct_protocol(device_id, bytes("AT+RESET\r\n", 'utf-8')), 'utf-8'))

            self.log(f"发送到 {client_ip}:{client_port}: {command_str}", "send")
        except Exception as e:
            self.log(f"发送命令失败: {str(e)}", "error")
            # 如果发送失败，很可能连接已断开，更新客户端列表
            self.after(0, self.update_client_list)

    def log(self, message, tag="info"):
        """添加日志信息"""
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        log_entry = f"[{timestamp}] {message}\n"

        self.log_text.config(state=NORMAL)
        self.log_text.insert(END, log_entry, tag)
        self.log_text.see(END)  # 滚动到最后
        self.log_text.config(state=DISABLED)

    def on_close(self):
        """关闭窗口时的处理"""
        if self.is_running:
            self.toggle_server()
        self.destroy()

    def create_widgets(self):
        pass
